#include "mdiWindow.h"


mdiWindow::mdiWindow(bakalarka *win): mainWin(win){
	
	model = 0;
	area = 0;
	force = false;
	setWindowIcon(QIcon(":img/lego.png"));

}

bool mdiWindow::readFile(const QString &fileName){

        std::ifstream file(fileName.toLatin1(), std::ios_base::binary);
	reader read(&file);
	lexical lex(&read);
	syntax syn(&lex);
	
	if(!file){
		QMessageBox::warning(this, tr("Vadny soubor"), tr("Soubor je poskozeny, nebo nemate prava na cteni."));
		return false;
	}
	QApplication::setOverrideCursor(Qt::WaitCursor);
	read.initialize();
	try{
		syn.getContainer(container);
	}
	catch(reader::bufferOverflow &e){
		QApplication::restoreOverrideCursor();
		QMessageBox::warning(this, tr("Zavazna udalost"), tr("Nastala zavazna chyba, oznamte ji Honzovi."));
		return false;
	}
	catch(std::ifstream::failure &e){
		QApplication::restoreOverrideCursor();
		QMessageBox::warning(this, tr("Vadny soubor"), tr("Soubor je poskozeny, nebo nemate prava na cteni."));
		return false;
	}
	catch(syntax::parseError &e){
		QApplication::restoreOverrideCursor();
		QString reason(e.what());
		syntaxError dialog(this, reason, e.getLine());

		dialog.setFileView(fileName);
		dialog.exec();
		if(dialog.getState() == syntaxError::EDIT){
			textEditDialog dialog(this);
		
			dialog.setFile(fileName);
			dialog.resize(640, 480);
			dialog.exec();
			if(dialog.isModified()){
				QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(parent());
				QMdiArea *mdi = qobject_cast<QMdiArea *>(subWindow->mdiArea());
				bakalarka *top = qobject_cast<bakalarka *>(mdi->parent());
				
				top->newMdiWindow(fileName);
			}
		}
			
		//QMessageBox::warning(this, tr("Chyba pri parsovani"), tr("Nastala chyba pri parsovani, zkontrolujte obsah souboru."));
		return false;
	}
	if(container.size() == 0){
		QApplication::restoreOverrideCursor();
		QMessageBox::warning(this, tr("Prazdny soubor"), tr("Soubor je prazdny nebo neobsahuje zadne objekty."));
		return false;
	}
	QApplication::restoreOverrideCursor();
	return true;

}

bool mdiWindow::loadSourceFile(const QString &fileName){

	if(!readFile(fileName))
		return false;
	area = new drawArea(this, &container);
	model = new containerModel(&container, this);
	QApplication::restoreOverrideCursor();
	connect(area, SIGNAL(realPosF(QPointF *)), 
		mainWin, SLOT(showCoordinates(QPointF *)));
	connect(area, SIGNAL(gObjectDoubleClicked(gObject *)), 
		mainWin, SLOT(showObject(gObject *)));
	connect(area, SIGNAL(gObjectDoubleClicked(gObject *)), 
		model, SLOT(setActiveGObject(gObject *)));
	connect(area, SIGNAL(scaleChanged()), 
		mainWin, SLOT(setScale()));
	connect(area, SIGNAL(changedSignal(drawArea *)), 
		this, SLOT(modified(drawArea *)));
	connect(area, SIGNAL(gTypeGoClicked(gTypeGo *, const QPointF &)), 
		mainWin, SLOT(areaClicked(gTypeGo *, const QPointF &)));
	connect(&fileWatcher, SIGNAL(fileChanged(const QString &)),
		this, SLOT(fileModified(const QString &)));
	setCurrentFile(fileName);
	fileWatcher.addPath(fileName);
	return true;

}

void mdiWindow::fileModified(const QString &fileName){
	
	fileWatcher.removePath(fileName);
	fileModifiedDialog dialog(this, fileName);
	
	QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(parent());
	
	dialog.exec();
	switch(dialog.getState()){
		case fileModifiedDialog::CLOSE:
			force = true;
			emit removeSubWindow(subWindow);
			break;
		case fileModifiedDialog::RELOAD:
			emit reloadSubWindow(subWindow);
			break;
		case fileModifiedDialog::SAVE:
			saveAs();
			break;
	}
	
}

containerModel *mdiWindow::getModel(){

	return model;

}

void mdiWindow::setCurrentFile(const QString &fileName){
	
	curFile = QFileInfo(fileName).canonicalFilePath();
	setWindowModified(false);
	setWindowTitle(userFriendlyCurrentFile() + "[*]");
 
}

QString mdiWindow::userFriendlyCurrentFile(){
	
	return strippedName(curFile);
 
}

QString &mdiWindow::currentFile(){

	return curFile;

}

QString mdiWindow::strippedName(const QString &fullFileName){
	
     return QFileInfo(fullFileName).fileName();
	 
}

void mdiWindow::resizeEvent(QResizeEvent *event){
	
	const QSize &size = event->size();
	
	if(area)
		area->resize(size.width(), size.height());
	
}

gObject *mdiWindow::getActiveObject(){
	
	const controlPoints &control = area->getControl();
	
	if(control.isDoubleClicked()){
		return control.getDoubleClickedGObject();
	}
	return 0;

}

drawArea *mdiWindow::getDrawArea(){

	return area;

}

void mdiWindow::modified(drawArea *area){

	setWindowModified(area->getChanged());

}

bool mdiWindow::copyFiles(std::stringstream &source, QString &target) const{

	QFile fileTarget(target);
	char buffer[COPY_BUFFER_LEN];
	
        if(!fileTarget.open(QIODevice::WriteOnly)){
		fileTarget.close();
		return false;
	}
	while(!source.eof()){
		source.read(buffer, COPY_BUFFER_LEN);
		fileTarget.write(buffer, source.gcount());
	}
	fileTarget.close();
	return true;

}

void mdiWindow::offsetBackup(QList<backupItem> &list) const{

	gObjectContainer::const_iterator iter = container.begin();
	gObject *object;
	struct backupItem item;

	for(; iter != container.end(); iter++){
		object = *iter;
		item.startOffset = object->getStartOffset();
		item.length = object->getLength();
		list.append(item);
	}

}

void mdiWindow::flushBackup(QList<backupItem> &list) const{

	unsigned i = 0;
	gObject *object;

	for(; i < container.size(); i++){
		object = container[i];
		object->setOffsets(list[i].startOffset, list[i].length);
	}

}

bool mdiWindow::save(QString fileName){

        std::ifstream readFile(curFile.toLatin1(), std::ios::binary);
        std::stringstream tempFile(std::ios::out | std::ios::in | std::ios::binary);
	QList<backupItem> list;

	fileWatcher.removePath(currentFile());
	if(!readFile){
		QMessageBox::warning(this, tr("Chyba zapisu"), tr("Poskozeny vstupni soubor."));
		return false;
	}
	
	serialize serial(&tempFile, &readFile);
	
	offsetBackup(list);
    QApplication::setOverrideCursor(Qt::WaitCursor);
	try{
		serial.writeGContainer(container);
	}
	catch(std::ifstream::failure &e){
		QApplication::restoreOverrideCursor();
		QMessageBox::warning(this, tr("Chyba zapisu"), tr("Nastala chyba pri serializaci."));
		readFile.close();
		return false;
	}
	if(!copyFiles(tempFile, fileName)){
		QApplication::restoreOverrideCursor();
		QMessageBox::warning(this, tr("Chyba zapisu"), tr("Vystupni soubor je nepouzitelny."));
		flushBackup(list);
		readFile.close();
		return false;
	}
	QApplication::restoreOverrideCursor();
	setCurrentFile(fileName);
	area->setChanged(false);
	readFile.close();
	fileWatcher.addPath(currentFile());
	return true;

}

bool mdiWindow::saveAs(){

	QString fileName = QFileDialog::getSaveFileName(this, tr("Ulozit jako"), curFile);
	
	if(fileName.isEmpty())
		return false;
	return save(fileName);
	
}

void mdiWindow::closeEvent(QCloseEvent *event){
	
	emit saveWindowHistory(*this);
	if(!force && area && area->getChanged()){
		saveOrNot saveDialog(this, curFile);
	
		saveDialog.exec();
		switch(saveDialog.getState()){
			case saveOrNot::YES:
				if(!saveAs())
					event->ignore();
                else
                    event->accept();
				break;
			case saveOrNot::NO:
				event->accept();
				break;
			case saveOrNot::CANCEL:
				event->ignore();
				break;
		}
	}
    if(event->isAccepted())
        emit closeSignal(model);
	
}

void mdiWindow::turnOffWatcher(){

	fileWatcher.removePath(currentFile());

}

gObjectContainer *mdiWindow::getContainer(){

	return &container;

}
